/************************************************************************
Copyright (c) 2010, 2013, C.R. All rights reserved. 

E-mail: crtoyou@gmail.com; crtoyou@163.com

You can redistribute it and/or modify it under the terms of the
GNU Lesser General Public License as published by the
Free Software Foundation version 3 of the License.

This source code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. if not, write to the Free Software Foundation, Inc., 
51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
************************************************************************/

#ifndef __CR_BYTE_STREAM_FILTER_H__
#define __CR_BYTE_STREAM_FILTER_H__

#include <crdebug.h>
#include <crstream.h>

namespace cr {

struct fakepusher { inline void push(byte&); };
template <class type_next_pusher = fakepusher>
class pusher_base
{
public:
	pusher_base() : next(NULL) {}
	inline void setnext(type_next_pusher* pusher) {next = pusher;}
	/*{{ it should be overwritten as public access
	inline void push(byte ch);
	}}*/
protected:
	type_next_pusher* next;
	// you can call yield any where if yield a byte or some repeat of a byte
	inline void pass(byte ch) const {ASSERT(next); next->push(ch);}
};

struct fakepuller { inline void pull(byte&); };
template <class type_next_puller = fakepuller>
class puller_base
{
public:
	puller_base() : next(NULL) {}
	inline void setnext(type_next_puller* pusher) {next = pusher;}
	/*{{ it should be overwritten as public access
	inline byte pull();
	}}*/
protected:
	type_next_puller* next;
	// you can call yield any where if yield a byte or some repeat of a byte
	inline byte pass() const {ASSERT(next); return next->pull();}
};

class direct_pusher : public pusher_base<>
{
public:
	inline void push(byte ch) { strm.putbyte(ch); }
	inline void input(const byte* buf, size_t len) { while(len--) push(*buf++); }
	direct_pusher(ostream_base& os) : strm(os) {}
protected:
	ostream_base& strm;
};

class direct_puller : public puller_base<>
{
public:
	inline byte pull() { return strm.getbyte(); }
	direct_puller(istream_base& is) : strm(is) {}
protected:
	istream_base& strm;
};

}//namespace

#endif//__CR_BYTE_STREAM_FILTER_H__